package cz.possoft.serializable.clovece.game;

import java.util.Collection;
import java.util.HashSet;

import cz.possoft.converter.jaxb.JAXBGameConverter;
import cz.possoft.generic.utils.GenericUtils;
import cz.possoft.serializable.clovece.jaxb.CloveceJAXBGameConverter;
import cz.possoft.serializable.generic.Game;

/**
 * @author <a href="mailto:mposolda@gmail.com">Marek Posolda</a>
 */
public class CloveceGame extends Game<ClovecePole>
{
   public static final long serialVersionUID = 1006935;
      
   private int numberOfFigurekInBlackPlayerStart;
   private int numberOfFigurekInWhitePlayerStart;
   
   private int[] locationOfWhiteFigurkas = new int[4];
   private int[] locationOfBlackFigurkas = new int[4];
   
   // Each player can play 3 times when figurky are at home. This fields are indicator of how many times player already played when all are at home (valid values 1-3)
   private int numberOfTahuWhenAllAreAtHome = 0;   
   
   public CloveceGame()
   {      
   }
   
   // pri konstrukci neni hra vubec inicializovana. Sachovnice i jmena hracu zustavaji prazdne
   public CloveceGame setNoGame() 
   {
       super.setNoGame();
       setHraciPole(new ClovecePole());
       
       // nobody is on the start if game is not active
       numberOfFigurekInBlackPlayerStart = 0;
       numberOfFigurekInWhitePlayerStart = 0;
       
       for (int i=0 ; i<4 ; i++)
       {
          locationOfWhiteFigurkas[i] = 0;
          locationOfBlackFigurkas[i] = 0;
       }
       
       return this;
   }
   
   // hra je nastavena do stavu, ktery nastava pri standardne pri nove hre.
   public CloveceGame setNewGameState(String whitePlayerName, String blackPlayerName, boolean iAmWhite) 
   {
       super.setNewGameState(whitePlayerName, blackPlayerName, iAmWhite);
       setHraciPole(new ClovecePole());
       
       // Both players have 4 figurky on the start when game starts.
       numberOfFigurekInBlackPlayerStart = 4;
       numberOfFigurekInWhitePlayerStart = 4;
       for (int i=0 ; i<4 ; i++)
       {
          CloveceField whiteStartField = getHraciPole().getStartField(i, GenericUtils.COLOR_WHITE);
          whiteStartField.setColor(GenericUtils.COLOR_WHITE);
          locationOfWhiteFigurkas[i] = whiteStartField.getId();
          
          CloveceField blackStartField = getHraciPole().getStartField(i, GenericUtils.COLOR_BLACK);
          blackStartField.setColor(GenericUtils.COLOR_BLACK);
          locationOfBlackFigurkas[i] = blackStartField.getId();
       }
       
       return this;
   }
   
   /**
    * get all figurkas, which can play for given color and given 'pocetTahu'. 
    * 
    * @param color
    * @param pocetTahu
    * @return collection of all fields, which can play.
    */
   public Collection<CloveceField> getAllFigurkasWhichCanPlay(int color, int pocetTahu)
   {
      Collection<CloveceField> result = new HashSet<CloveceField>();      
      
      int[] locationOfFigurkas = color==GenericUtils.COLOR_WHITE ? locationOfWhiteFigurkas : locationOfBlackFigurkas;
      for (int i=0 ; i<4 ; i++)
      {
         int loc = locationOfFigurkas[i];
            
            CloveceField curField = getHraciPole().getFieldById(loc);            

            // we can add field if there are some fields where that figurka can play
            if (getHraciPole().getFieldsWhereFigurkaCanPlay(curField, pocetTahu, color).size() > 0)
            {
               result.add(curField);
            }
      }
      
      System.out.println("getAllFigurkasWhichCanPlay: " + color + " " + pocetTahu + " " + result);
      return result;
   }
   
   /**
    * send from UI as notification that we should move figurka from field 'fieldFrom' to field 'fieldTo'.    
    * 
    * @param pocetTahu
    * @param fieldFrom
    * @param fieldTo
    * @return 0 - if next 'tah' will be performed by opponent.
    *         1 - if we will play again (resp. current player will play again), This happen only if pocetTahu == 6
    *         2 - if game is finished and we (current player) win 
    */
   public int handlePlayingWithFigurkas(int pocetTahu, CloveceField fieldFrom, CloveceField fieldTo)
   {
      int color = fieldFrom.getColor();

      // moving out of figurka
      if (fieldTo.getColor() == GenericUtils.getOppositeColor(color))
      {
         handleMovingOutOfFigurka(fieldTo);
      }
      
      fieldTo.setColor(color);      
      fieldFrom.setColor(GenericUtils.COLOR_NEUTRAL); 
      
      if (color == GenericUtils.COLOR_WHITE)
      {
         // We are adding new figurka into the board
         if (fieldTo.getId() == ClovecePole.WHITE_PLAYER_START_FIELD_ON_BOARD)
         {
            numberOfFigurekInWhitePlayerStart--;
            numberOfTahuWhenAllAreAtHome = 0;
         }
         
         for (int i=0; i<4 ; i++)
         {
            if (locationOfWhiteFigurkas[i] == fieldFrom.getId())
            {
               locationOfWhiteFigurkas[i] = fieldTo.getId();
            }
         }
      }
      else
      {
         // We are adding new figurka into the board
         if (fieldTo.getId() == ClovecePole.BLACK_PLAYER_START_FIELD_ON_BOARD)
         {
            numberOfFigurekInBlackPlayerStart--;
            numberOfTahuWhenAllAreAtHome = 0;
         }
         
         for (int i=0; i<4 ; i++)
         {
            if (locationOfBlackFigurkas[i] == fieldFrom.getId())
            {
               locationOfBlackFigurkas[i] = fieldTo.getId();
            }
         }         
      }
      
      boolean gameFinished = checkGameFinishedForPlayer(color);
      if (gameFinished)
      {
         return 2;
      }
      else if (pocetTahu==6)
      {
         return 1;
      }
      else
      {
         return 0;
      }            
   }
   
   /**
    * Check if game in in state that current player is winner of the game
    * 
    * @param color
    * @return true if it is winner
    */
   private boolean checkGameFinishedForPlayer(int color)
   {
      for (int i=0 ; i<4 ; i++)
      {
         CloveceField homeField = getHraciPole().getHomeField(i, color);
         if (homeField.getColor() != color)
         {
            return false;
         }
      }
      
      return true;
   }
   
   /**
    * Handle moving out (Vyhozeni) of figurka.
    * 
    * @param fig
    */
   private void handleMovingOutOfFigurka(CloveceField fig)
   {
      int color = fig.getColor();
      fig.setColor(GenericUtils.COLOR_NEUTRAL);
      
      // find free location on starting fields
      CloveceField emptyStartField = null;            
      for (int i=0; i<4 ; i++)
      {
         CloveceField startField = getHraciPole().getStartField(i, color);
         if (startField.getColor() == GenericUtils.COLOR_NEUTRAL)
         {
            emptyStartField = startField;
            break;
         }
      }
      
      if (emptyStartField == null)
      {
         throw new IllegalStateException("We can't move out figurka to starting location because there is no free starting location.");
      }
      
      emptyStartField.setColor(color);
      
      // upgrade number of figurkas on starting fields
      if (color == GenericUtils.COLOR_WHITE)
      {
         numberOfFigurekInWhitePlayerStart++;
      }
      else
      {
         numberOfFigurekInBlackPlayerStart++;
      }
      
      // upgrade locations
      int[] locations = color==GenericUtils.COLOR_WHITE ? locationOfWhiteFigurkas : locationOfBlackFigurkas;
      for (int i=0; i<4 ; i++)
      {
         if (locations[i] == fig.getId())
         {
            locations[i] = emptyStartField.getId();
         }
      }
   }
   
   /**
    * it returns true, if player can do something after playing with cube. It return false, if player can't do nothing and so 
    * opponent is "na tahu". 
    * 
    * Method will return true also for the case when our player has all figurkas still on start fields and 
    * he didn't play for 3 times. In this case, counter will be incremented.
    * 
    * @param color
    */
   public boolean isPlayerStillOnGameAfterPlayingWithCube(int color, int pocetTahu)
   {
      Collection<CloveceField> permittedFields = getAllFigurkasWhichCanPlay(color, pocetTahu);
      if (permittedFields.size() != 0)
      {
         return true;
      }
      else
      {
         int numberOfFigurekOnStart = color==GenericUtils.COLOR_WHITE ? numberOfFigurekInWhitePlayerStart : numberOfFigurekInBlackPlayerStart;
         if (numberOfFigurekOnStart == 4)
         {
            numberOfTahuWhenAllAreAtHome++;
            if (numberOfTahuWhenAllAreAtHome == 3)
            {
               numberOfTahuWhenAllAreAtHome = 0;
               return false;
            }
            return true;
         }
         
         // we can also play again if pocetTahu == 6
         if (pocetTahu == 6)
         {
            return true;
         }
         
         return false;
      }
   }
   
   /**
    * location arrays for color of specified player (used for converter purpose)
    * 
    * @param color
    * @return
    */
   public int[] getLocationOfPlayer(int color)
   {
      if (color == GenericUtils.COLOR_WHITE)
      {
         return locationOfWhiteFigurkas;
      }
      else if (color == GenericUtils.COLOR_BLACK)
      {
         return locationOfBlackFigurkas;
      }
      else
      {
         throw new IllegalArgumentException("Illegal argument " + color);
      }
   }
   
   /**
    * set location and update all other fields based on set locations.
    * 
    * @param color
    * @param locations
    */
   public void setLocationOfPlayer(int color, int[] locations)
   {
      if (locations.length != 4)
      {
         throw new IllegalArgumentException("Location length must be 4 but is " + locations.length);
      }
      
      if (color == GenericUtils.COLOR_WHITE)
      {
         locationOfWhiteFigurkas = locations;
         numberOfFigurekInWhitePlayerStart = 0;
         for (int i=0; i<4 ; i++)
         {
            if (locations[i]>=1000)
            {
               numberOfFigurekInWhitePlayerStart++;
            }
         }
      }
      else if (color == GenericUtils.COLOR_BLACK)
      {
         locationOfBlackFigurkas = locations;
         numberOfFigurekInBlackPlayerStart = 0;
         for (int i=0; i<4 ; i++)
         {
            if (locations[i]>=2000)
            {
               numberOfFigurekInBlackPlayerStart++;
            }
         }         
      }
      
      // update ClovecePole in 2 steps. 
      // step 1 - Delete old location of colors.
      for (int i=0 ; i<ClovecePole.LENGTH ; i++)
      {
         if (getHraciPole().getField(i).getColor() == color)
         {
            getHraciPole().getField(i).setColor(GenericUtils.COLOR_NEUTRAL);
         }
      }
      for (int i=0 ; i<4 ; i++)
      {
         if (getHraciPole().getStartField(i, color).getColor() == color)
         {
            getHraciPole().getStartField(i, color).setColor(GenericUtils.COLOR_NEUTRAL);
         }
         if (getHraciPole().getHomeField(i, color).getColor() == color)
         {
            getHraciPole().getHomeField(i, color).setColor(GenericUtils.COLOR_NEUTRAL);
         }         
      }      
      
      // step 2 - update new locations in ClovecePole
      for (int i=0; i<4 ; i++)
      {
         getHraciPole().getFieldById(locations[i]).setColor(color);
      }
   }
   
   public JAXBGameConverter<CloveceGame> getJAXBGameConverter() 
   {      
      return CloveceJAXBGameConverter.getInstance();
   }     
   
}

